﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Ec.NETCoreFramework.Common;
using Ec.NETCoreFramework.Common.Core;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;

namespace Ec.NETCoreFramework.Common.Cache
{
    /// <summary>
    /// 分布式redis
    /// </summary>
    public class RedDistributedLock: IRedDistributedLock
    {
        /// <summary>
        /// 线程同步变量
        /// </summary>
        private static object syncObj = new object();
        private static RedLockFactory _instance = null;
        public RedDistributedLock(string[] server)
        {
            InitLockFactory(server);
        }
        private RedLockFactory InitLockFactory(string[] server)
        {
            if (_instance == null)
            {
                lock (syncObj)
                {
                    if (_instance == null)
                    {

                        if (server.Length <= 0)
                        {
                            throw new ArgumentException("server 不能为空");
                        }
                        var endPoints = new List<RedLockEndPoint>();
                        foreach (var item in server)
                        {
                            var arr = item.Split(":");
                            endPoints.Add(new DnsEndPoint(arr[0], Convert.ToInt32(arr[1])));
                        }
                        _instance = RedLockFactory.Create(endPoints);
                    }
                }
            }
            return _instance;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="resource"></param>
        /// <param name="expiryTime">锁定过期时间，锁区域内的逻辑执行如果超过过期时间，锁将被释放</param>
        /// <param name="waitTime">等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间</param>
        /// <param name="work">回调整函数</param>
        /// <returns></returns>
        public async Task<IResponse> BlockingWork(string resource, TimeSpan expiryTime, TimeSpan waitTime, Func<Task<IResponse>> work)
        {
            // resource 锁定的对象
            // expiryTime 锁定过期时间，锁区域内的逻辑执行如果超过过期时间，锁将被释放
             // waitTime 等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
            // retryTime 等待时间内，多久尝试获取一次

            resource = CreateKey(resource);
            using (var redisLockFactory = await _instance.CreateLockAsync(resource, expiryTime, waitTime, TimeSpan.FromSeconds(1)))
            {
                // blocks until acquired or 'wait' timeout
                if (redisLockFactory.IsAcquired)
                {
                    return await work();
                }
                return FrameworkResponse.SystemError("redisLockFactory.IsAcquired:false");
            }
        }
        /// <summary>
        /// 重新设置键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private string CreateKey(string key)
        {
            return string.Join("_", "REDLOCK", key);
        }
    }
}
